package com.freewater.parking.domain.parking;

import com.freewater.parking.domain.blacklist.BlackListRepository;
import com.freewater.parking.domain.blacklist.InBlackListException;
import com.freewater.parking.domain.common.EventQueue;
import com.freewater.parking.domain.common.PlateNumber;

import java.time.LocalDateTime;

public class ParkingServiceImpl implements ParkingService {

    private final BlackListRepository blackLists;
    private final FeeCalculator feeCalculator;

    public ParkingServiceImpl(BlackListRepository blackLists,
                              FeeCalculator feeCalculator) {
        this.blackLists = blackLists;
        this.feeCalculator = feeCalculator;
    }

    @Override
    public boolean checkIn(EventQueue queue,
                           Parking parking,
                           LocalDateTime checkInTime) throws InBlackListException {
        PlateNumber plateNumber = parking.getPlateNumber();
        boolean inBlackList = this.blackLists.existsById(plateNumber);
        if (inBlackList) {
            throw new InBlackListException("黑名单车牌号，禁止入场");
        }
        return parking.checkIn(queue, checkInTime);
    }

    @Override
    public int calcParkingFee(EventQueue queue,
                              Parking parking,
                              LocalDateTime time) {
        int totalFee = this.calcTotalFee(parking, time);
        // 需要支付的费用减去已支付费用即为未结清的停车费
        return parking.calcUnPaidFee(totalFee);
    }

    @Override
    public void payParkingFee(EventQueue queue,
                              Parking parking,
                              int payMoney,
                              LocalDateTime payTime) {
        int totalFee = this.calcTotalFee(parking, payTime);
        parking.payParkingFee(queue, totalFee, payMoney, payTime);
    }

    @Override
    public boolean checkOut(EventQueue queue,
                            Parking parking,
                            LocalDateTime checkOutTime) {
        int totalFee = this.calcTotalFee(parking, checkOutTime);
        return parking.checkOut(queue, totalFee, checkOutTime);
    }

    /**
     * 计算停车费：<br/>
     * 如果在上一次完成支付后的15分钟内，则不持续计费；<br/>
     *
     * @param parking      停车
     * @param checkOutTime 离场时间
     * @return 停车费
     */
    private int calcTotalFee(Parking parking, LocalDateTime checkOutTime) {
        if (!parking.isInPark()) {
            throw new NotCheckedInException("车辆不在场");
        }
        final PlateNumber plateNumber = parking.getPlateNumber();
        final LocalDateTime checkInTime = parking.getCheckInTime();
        final LocalDateTime payTime = parking.getLastPayTime();
        FeeCalcSpecification specification = new FeeCalcSpecification(plateNumber,
                checkInTime,
                checkOutTime,
                payTime);
        return this.feeCalculator.calcParkingFee(specification);
    }
}
